home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / libs / intuisup.lha / Intuisup / source.lha / Gadgets / gadgets3.c < prev    next >
C/C++ Source or Header  |  1992-08-19  |  29KB  |  921 lines

  1. /* $Revision Header *** Header built automatically - do not edit! ***********
  2.  *
  3.  *    (C) Copyright 1991 by Torsten Jürgeleit
  4.  *
  5.  *    Name .....: gadgets3.c
  6.  *    Created ..: Thursday 19-Dec-91 20:52:56
  7.  *    Revision .: 5
  8.  *
  9.  *    Date        Author                 Comment
  10.  *    =========   ====================   ====================
  11.  *    19-Aug-92   Torsten Jürgeleit      save old clipping rectangles in
  12.  *                       print_list_view_text()
  13.  *    06-Aug-92   Torsten Jürgeleit      alternate entry text color in
  14.  *                       print_list_view_text()
  15.  *    01-Apr-92   Torsten Jürgeleit      any references to gadget data
  16.  *                       via gl_Data removed
  17.  *    06-Jan-92   Torsten Jürgeleit      added pop up cycle text list
  18.  *    28-Dec-91   Torsten Jürgeleit      correct output of count gadget value
  19.  *                       if ri_ScreenDepth == 1
  20.  *    19-Dec-91   Torsten Jürgeleit      Created this file!
  21.  *
  22.  ****************************************************************************
  23.  *
  24.  *    Gadget support routines - part 3
  25.  *
  26.  * $Revision Header ********************************************************/
  27.  
  28.     /* Includes */
  29.  
  30. #include <exec/types.h>
  31. #include <exec/memory.h>
  32. #include <devices/inputevent.h>
  33. #include <intuition/intuition.h>
  34. #ifdef AZTEC_C
  35. #include <functions.h>   /* needed for Aztec C - prototypes and pragmas for all Amiga system functions */
  36. #endif
  37. #include <libraries/memwatch.h>   /* header file for memory debug link library (Fish 240) - AFTER functions.h */
  38. #include <string.h>
  39. #include "/render/render.h"
  40. #include "/texts/texts.h"
  41. #include "/borders/borders.h"
  42. #include "/language/language.h"
  43. #include "gadgets.h"
  44. #include "imports.h"
  45.  
  46.     /* Refresh full ISUP gadget */
  47.  
  48.    VOID
  49. refresh_gadget(struct ExtendedGadget  *egad)
  50. {
  51.    struct GadgetList  *gl = egad->eg_GadgetList;
  52.  
  53.    if (gl->gl_Flags & GADGET_LIST_FLAG_DISPLAYED) {
  54.       struct RenderInfo      *ri = gl->gl_RenderInfo;
  55.       struct Window          *win = gl->gl_Window;
  56.       struct RastPort        *rp = win->RPort;
  57.       struct ExtendedGadget  *first_egad = egad;
  58.  
  59.       /* Render object text - rendering first because of ghosting by GADGDISABLED */
  60.       switch (egad->eg_DataType) {
  61.      case GADGET_DATA_TYPE_CYCLE :
  62.         print_cycle_text(egad);
  63.         break;
  64.  
  65.      case GADGET_DATA_TYPE_COUNT :
  66.         print_count_text(egad, TRUE);
  67.         break;
  68.  
  69.      case GADGET_DATA_TYPE_LISTVIEW :
  70.         print_list_view_text(egad);
  71.         break;
  72.       }
  73.       print_gadget_text(first_egad);
  74.  
  75.       /* Render all gadgets belonging to this ISUP object */
  76.       do {
  77.      struct Gadget  *gad = &egad->eg_Gadget;
  78.      UBYTE flags = egad->eg_Flags;
  79.  
  80.      /* Draw additional border or image if any */
  81.      if (flags & (EXTENDED_GADGET_FLAG_RENDER_BORDER |
  82.                        EXTENDED_GADGET_FLAG_RENDER_IMAGE)) {
  83.         SHORT left_edge = gad->LeftEdge, top_edge = gad->TopEdge;
  84.  
  85.         if (flags & EXTENDED_GADGET_FLAG_RENDER_BORDER) {
  86.            DrawBorder(rp, (struct Border *)egad->eg_Render,
  87.                        (LONG)left_edge, (LONG)top_edge);
  88.         } else {
  89.            struct Image  *image = (struct Image *)egad->eg_Render;
  90.  
  91.            SHORT xoffset = (first_egad->eg_DataFlags &
  92.                         GADGET_DATA_FLAG_NO_BORDER ?
  93.                    IMAGE_HORIZ_OFFSET : IMAGE_HORIZ_OFFSET + 2),
  94.              width = gad->Width;
  95.  
  96.            top_edge += (SHORT)(gad->Height - image->Height) / 2;
  97.            switch (egad->eg_Type) {
  98.           case EXTENDED_GADGET_TYPE_CYCLE :
  99.              left_edge += xoffset;
  100.              break;
  101.  
  102.           case EXTENDED_GADGET_TYPE_COUNT :
  103.              DrawImage(rp, &ri->ri_Images[IMAGE_COUNT_RIGHT],
  104.              (LONG)(left_edge + width - image->Width - xoffset),
  105.                                 (LONG)top_edge);
  106.              left_edge += xoffset;
  107.              break;
  108.  
  109.           default :
  110.              left_edge += (SHORT)(width - image->Width) / 2;
  111.              break;
  112.            }
  113.            DrawImage(rp, image, (LONG)left_edge, (LONG)top_edge);
  114.         }
  115.      }
  116.  
  117.      /* Check if disabled selected toggle select gadget */
  118.      if ((gad->Activation & TOGGLESELECT) && (gad->Flags &
  119.           (GADGDISABLED | SELECTED)) == (GADGDISABLED | SELECTED)) {
  120.         APTR render = gad->GadgetRender;
  121.  
  122.         /* Special refresh to force correct ghosting */
  123.         gad->GadgetRender = gad->SelectRender;
  124.         gad->Flags       &= ~SELECTED;
  125.         RefreshGList(gad, win, (LONG)NULL, 1L);
  126.         gad->Flags       |= SELECTED;
  127.         gad->GadgetRender = render;
  128.      } else {
  129.  
  130.         /* Normal refresh */
  131.         RefreshGList(gad, win, (LONG)NULL, 1L);
  132.      }
  133.       } while (egad = egad->eg_NextGadget);
  134.    }
  135. }
  136.     /* Change gadget */
  137.  
  138.    VOID
  139. change_gadget(struct ExtendedGadget  *egad)
  140. {
  141.    struct GadgetList    *gl = egad->eg_GadgetList;
  142.    struct Window        *win = gl->gl_Window;
  143.    struct Gadget        *gad = &egad->eg_Gadget;
  144.    struct PropInfo      *pinfo;
  145.    struct MXData        *mx;
  146.    struct SliderData    *sl;
  147.    struct CycleData     *cy;
  148.    struct ScrollerData  *sc;
  149.    struct ListViewData  *lv;
  150.    struct PaletteData   *pd;
  151.    VOID   *data = (VOID *)(egad + 1);
  152.    ULONG  min, max, num, body, pot, flags = egad->eg_DataFlags;
  153.    UBYTE  displayed = gl->gl_Flags & GADGET_LIST_FLAG_DISPLAYED;
  154.    USHORT i;
  155.  
  156.    switch (egad->eg_DataType) {
  157.       case GADGET_DATA_TYPE_BUTTON :
  158.       case GADGET_DATA_TYPE_CHECK :
  159.       case GADGET_DATA_TYPE_STRING :
  160.       case GADGET_DATA_TYPE_INTEGER :
  161.      if (displayed) {
  162.         RefreshGList(gad, win, (LONG)NULL, 1L);
  163.      }
  164.      break;
  165.  
  166.       case GADGET_DATA_TYPE_MX :
  167.      mx  = data;
  168.      max = mx->mx_TextEntries;
  169.      num = mx->mx_ActiveEntry;
  170.      for (i = 0; i < max; i++) {
  171.         gad = &egad->eg_Gadget;
  172.         if (i == num) {
  173.            gad->Flags |= SELECTED;
  174.            if (displayed) {
  175.           RefreshGList(gad, win, (LONG)NULL, 1L);
  176.            }
  177.         } else {
  178.            if (gad->Flags & SELECTED) {
  179.           gad->Flags &= ~SELECTED;
  180.           if (displayed) {
  181.              RefreshGList(gad, win, (LONG)NULL, 1L);
  182.           }
  183.            }
  184.            
  185.         }
  186.         egad = egad->eg_NextGadget;
  187.      }
  188.      break;
  189.  
  190.       case GADGET_DATA_TYPE_SLIDER :
  191.      pinfo = (struct PropInfo *)gad->SpecialInfo;
  192.      sl    = data;
  193.      min   = sl->sl_Min;
  194.      max   = (LONG)sl->sl_Max - (LONG)min;
  195.      num   = (LONG)sl->sl_Level - (LONG)min;
  196.      if (flags & GADGET_DATA_FLAG_ORIENTATION_VERT) {
  197.         num = max - num;   /* if vert slider then maximum is at top */
  198.      }
  199.      body = calc_prop_body(max + 1, 1L);
  200.      pot  = calc_prop_pot(max + 1, 1L, num);
  201.      if (flags & GADGET_DATA_FLAG_ORIENTATION_VERT) {
  202.         if (displayed) {
  203.            NewModifyProp(gad, win, (LONG)NULL, (LONG)pinfo->Flags, 0L,
  204.                              pot, 0L, body, 1L);
  205.         } else {
  206.            pinfo->VertBody = body;
  207.            pinfo->VertPot  = pot;
  208.         }
  209.      } else {
  210.         if (displayed) {
  211.            NewModifyProp(gad, win, (LONG)NULL, (LONG)pinfo->Flags, pot,
  212.                               0L, body, 0L, 1L);
  213.         } else {
  214.            pinfo->HorizBody = body;
  215.            pinfo->HorizPot  = pot;
  216.         }
  217.      }
  218.      break;
  219.  
  220.       case GADGET_DATA_TYPE_SCROLLER :
  221.      pinfo = (struct PropInfo *)gad->SpecialInfo;
  222.      sc    = data;
  223.      min   = sc->sc_Visible;
  224.      max   = sc->sc_Total;
  225.      num   = sc->sc_Top;
  226.      body  = calc_prop_body(max, min);
  227.      pot   = calc_prop_pot(max, min, num);
  228.      if (flags & GADGET_DATA_FLAG_ORIENTATION_VERT) {
  229.         if (displayed) {
  230.            NewModifyProp(gad, win, (LONG)NULL, (LONG)pinfo->Flags, 0L,
  231.                              pot, 0L, body, 1L);
  232.         } else {
  233.            pinfo->VertBody = body;
  234.            pinfo->VertPot  = pot;
  235.         }
  236.      } else {
  237.         if (displayed) {
  238.            NewModifyProp(gad, win, (LONG)NULL, (LONG)pinfo->Flags, pot,
  239.                               0L, body, 0L, 1L);
  240.         } else {
  241.            pinfo->HorizBody = body;
  242.            pinfo->HorizPot  = pot;
  243.         }
  244.      }
  245.      break;
  246.  
  247.       case GADGET_DATA_TYPE_CYCLE :
  248.      cy                = data;
  249.      cy->cy_ActiveText = cy->cy_TextArray[cy->cy_ActiveEntry];
  250.      if (displayed) {
  251.         print_cycle_text(egad);
  252.      }
  253.      break;
  254.  
  255.       case GADGET_DATA_TYPE_COUNT :
  256.      if (displayed) {
  257.         print_count_text(egad, TRUE);
  258.      }
  259.      break;
  260.  
  261.       case GADGET_DATA_TYPE_LISTVIEW :
  262.      pinfo = (struct PropInfo *)gad->SpecialInfo;
  263.      lv    = data;
  264.      min   = lv->lv_VisibleEntries;
  265.      max   = lv->lv_ListEntries;
  266.      num   = lv->lv_TopEntry;
  267.      body  = calc_prop_body(max, min);
  268.      pot   = calc_prop_pot(max, min, num);
  269.      if (displayed) {
  270.         NewModifyProp(gad, win, (LONG)NULL, (LONG)pinfo->Flags, 0L, pot,
  271.                                   0L, body, 1L);
  272.         print_list_view_text(egad);
  273.      } else {
  274.         pinfo->VertBody = body;
  275.         pinfo->VertPot  = pot;
  276.      }
  277.      break;
  278.  
  279.       case GADGET_DATA_TYPE_PALETTE :
  280.      pd = data;
  281.      if (!(flags & GADGET_DATA_FLAG_PALETTE_NO_INDICATOR)) {
  282.         struct Image  *image = (struct Image *)egad->eg_Render;
  283.  
  284.         image->PlaneOnOff = pd->pd_ActiveColor;
  285.         if (displayed) {
  286.            DrawImage(win->RPort, image, (LONG)(gad->LeftEdge + (SHORT)
  287.              (gad->Width - image->Width) / 2), (LONG)(gad->TopEdge +
  288.                  (SHORT)(gad->Height - image->Height) / 2));
  289.         }
  290.      }
  291.      break;
  292.    }
  293. }
  294.     /* Change cycle gadget text */
  295.  
  296.    BOOL
  297. change_cycle_gadget(struct ExtendedGadget  *egad, ULONG qualifier)
  298. {
  299.    struct Window     *win = egad->eg_GadgetList->gl_Window;
  300.    struct MsgPort    *up  = win->UserPort;
  301.    struct Gadget     *gad = &egad->eg_Gadget;
  302.    struct CycleData  *cy = (struct CycleData *)(egad + 1);
  303.    LONG   entry, old_entry = cy->cy_ActiveEntry;
  304.    ULONG  old_idcmp_flags = win->IDCMPFlags;
  305.    USHORT delay = MAX_CYCLE_DELAY;
  306.    BOOL   keepon = TRUE, changed = FALSE;
  307.  
  308.    /* Wait a while before using popup cycle text list */
  309.    ModifyIDCMP(win, (LONG)(MOUSEBUTTONS | INTUITICKS));
  310.    do {
  311.       struct IntuiMessage  *msg;
  312.  
  313.       WaitPort(up);
  314.       if (msg = (struct IntuiMessage *)GetMsg(up)) {
  315.      switch (msg->Class) {
  316.         case INTUITICKS :
  317.            if (!--delay) {
  318.           keepon = FALSE;
  319.            }
  320.            break;
  321.  
  322.         case MOUSEBUTTONS :
  323.            if (msg->Code == SELECTUP) {
  324.           keepon = FALSE;
  325.            }
  326.            break;
  327.      }
  328.      ReplyMsg((struct Message *)msg);
  329.       }
  330.    } while (keepon == TRUE);
  331.    if (delay) {
  332.       LONG max_entry = cy->cy_TextEntries - 1;
  333.  
  334.       /* Get new entry entry by selection next or previous one */
  335.       if (qualifier & QUALIFIER_SHIFT) {
  336.      if (old_entry > 0) {
  337.         entry = old_entry - 1;
  338.      } else {
  339.         entry = max_entry;
  340.      }
  341.       } else {
  342.      if (old_entry < max_entry) {
  343.         entry = old_entry + 1;
  344.      } else {
  345.         entry = 0;
  346.      }
  347.       }
  348.    } else {
  349.  
  350.       /* Get new entry from pop up cycle text list */
  351.       if ((entry = pop_up_cycle_list(egad)) == -1L) {
  352.      entry = old_entry;
  353.       }
  354.    }
  355.    ModifyIDCMP(win, old_idcmp_flags);
  356.  
  357.    /* Restore normal cycle gadget state (unselected) */
  358.    if ((gad->Flags & GADGHIGHBITS) == GADGHCOMP) {
  359.       RefreshGList(gad, win, (LONG)NULL, 1L);   /* complement gadget select box */
  360.    }
  361.    gad->Flags &= ~SELECTED;
  362.    RefreshGList(gad, win, (LONG)NULL, 1L);
  363.  
  364.    /* Print new cycle text */
  365.    if (entry != old_entry) {
  366.       cy->cy_ActiveEntry = entry;
  367.       cy->cy_ActiveText  = cy->cy_TextArray[entry];
  368.       print_cycle_text(egad);
  369.       changed = TRUE;
  370.    }
  371.    return(changed);
  372. }
  373.     /* Select cycle entry from pop up cycle list */
  374.  
  375.    STATIC LONG
  376. pop_up_cycle_list(struct ExtendedGadget  *egad)
  377. {
  378.    struct GadgetList  *gl = egad->eg_GadgetList;
  379.    struct Window      *win = gl->gl_Window;
  380.    struct RastPort    *backup_rp, *rp = win->RPort;
  381.    struct CycleData   *cy = (struct CycleData *)(egad + 1);
  382.    SHORT  yinc, left_edge, top_edge;
  383.    USHORT width, height;
  384.    LONG   entry = -1L;
  385.  
  386.    /* Calc pop up list dimension and position */
  387.    width     = cy->cy_Width + 2 * CYCLE_POP_XOFFSET;
  388.    height    = cy->cy_EntryHeight * cy->cy_TextEntries +
  389.                               2 * CYCLE_POP_YOFFSET;
  390.    left_edge = cy->cy_LeftEdge - CYCLE_POP_XOFFSET;
  391.    top_edge  = cy->cy_TopEdge - CYCLE_POP_YOFFSET;
  392.  
  393.    /* If pop up list doesn't fit downwards then try it upwards */
  394.    if ((top_edge + height) > win->Height) {
  395.       top_edge -= height - (cy->cy_EntryHeight + 2 * CYCLE_POP_YOFFSET);
  396.       yinc      = -cy->cy_EntryHeight;
  397.  
  398.       /* If it doesn't fit upwards too then give up */
  399.       if (top_edge < 0) {
  400.      DisplayBeep(NULL);
  401.       }
  402.    } else {
  403.       yinc = cy->cy_EntryHeight;
  404.    }
  405.  
  406.    /* Create bitmap for saving pop up list background */
  407.    if (top_edge >= 0 && (backup_rp = create_rast_port(width, height,
  408.                           (USHORT)rp->BitMap->Depth))) {
  409.       struct MsgPort     *up = win->UserPort;
  410.       struct IntuiText  itext, *it = &itext;
  411.       BYTE   **text = cy->cy_TextArray;
  412.       USHORT xpos = left_edge + CYCLE_POP_XOFFSET,
  413.          ypos = top_edge + CYCLE_POP_YOFFSET,
  414.          detail_pen = win->DetailPen, block_pen = win->BlockPen;
  415.       LONG   last_entry = -1L;
  416.       BOOL   keepon = TRUE;
  417.  
  418.       /* Save old cycle list backgound and prepare new one */
  419.       ClipBlit(rp, (LONG)left_edge, (LONG)top_edge, backup_rp, 0L, 0L,
  420.                       (LONG)width, (LONG)height, 0xc0L);
  421.       SetDrMd(rp, (LONG)JAM1);
  422.       SetAPen(rp, (LONG)detail_pen);
  423.       RectFill(rp, (LONG)left_edge, (LONG)top_edge,
  424.           (LONG)(left_edge + width - 1), (LONG)(top_edge + height - 1));
  425.       SetAPen(rp, (LONG)block_pen);
  426.       RectFill(rp, (LONG)(left_edge + 2), (LONG)(top_edge + 1),
  427.           (LONG)(left_edge + width - 3), (LONG)(top_edge + height - 2));
  428.       SetDrMd(rp, (LONG)COMPLEMENT);
  429.  
  430.       /* Print cycle list text */
  431.       it->FrontPen  = detail_pen;
  432.       it->BackPen   = block_pen;
  433.       it->DrawMode  = JAM1;
  434.       it->LeftEdge  = xpos;
  435.       it->TopEdge   = (yinc > 0 ? ypos : ypos + height -
  436.                   (cy->cy_EntryHeight + 2 * CYCLE_POP_YOFFSET));
  437.       it->ITextFont = egad->eg_TextAttr;
  438.       it->NextText  = NULL;
  439.       while (*text) {
  440.      it->IText = (UBYTE *)get_language_text(*text++,
  441.                           gl->gl_LanguageTextArray);
  442.      PrintIText(rp, it, 0L, 0L);
  443.      it->TopEdge += yinc;
  444.       }
  445.  
  446.       /* Wait for release of left mouse button */
  447.       do {
  448.      struct IntuiMessage  *msg;
  449.  
  450.      WaitPort(up);
  451.      while (msg = (struct IntuiMessage *)GetMsg(up)) {
  452.         SHORT mouse_x = win->MouseX, mouse_y = win->MouseY;
  453.  
  454.         /* Check if mouse pointer is over pop up list entry */
  455.         if (mouse_x >= (left_edge + CYCLE_POP_XOFFSET) &&
  456.             mouse_x < (left_edge + width - 2 * CYCLE_POP_XOFFSET) &&
  457.             mouse_y >= (top_edge + CYCLE_POP_YOFFSET) &&
  458.             mouse_y < (top_edge + height - 2 * CYCLE_POP_YOFFSET)) {
  459.            LONG new_entry = (yinc > 0 ? (mouse_y - ypos) / yinc :
  460.              cy->cy_TextEntries - (mouse_y - ypos) / -yinc - 1);
  461.  
  462.            if (new_entry != last_entry) {
  463.           USHORT y;
  464.  
  465.           if (last_entry != -1L) {
  466.  
  467.              /* Unmark last selected entry */
  468.              y = ypos + CYCLE_LIST_ENTRY_YPOS(last_entry);
  469.              RectFill(rp, (LONG)xpos, (LONG)y, (LONG)(xpos + width -
  470.                          2 * CYCLE_POP_XOFFSET - 1),
  471.                     (LONG)(y + cy->cy_EntryHeight - 1));
  472.           }
  473.  
  474.           /* Mark selected entry */
  475.           y = ypos + CYCLE_LIST_ENTRY_YPOS(new_entry);
  476.           RectFill(rp, (LONG)xpos, (LONG)y, (LONG)(xpos + width -
  477.                          2 * CYCLE_POP_XOFFSET - 1),
  478.                     (LONG)(y + cy->cy_EntryHeight - 1));
  479.           last_entry = new_entry;
  480.            }
  481.         } else {
  482.            if (last_entry != -1L) {
  483.           USHORT y = ypos + CYCLE_LIST_ENTRY_YPOS(last_entry);
  484.  
  485.           /* Unmark last selected entry */
  486.           RectFill(rp, (LONG)xpos, (LONG)y, (LONG)(xpos + width -
  487.                          2 * CYCLE_POP_XOFFSET - 1),
  488.                     (LONG)(y + cy->cy_EntryHeight - 1));
  489.           last_entry = -1L;
  490.            }
  491.         }
  492.         if (msg->Class == MOUSEBUTTONS && msg->Code == SELECTUP) {
  493.            entry  = last_entry;
  494.            keepon = FALSE;
  495.         }
  496.         ReplyMsg((struct Message *)msg);
  497.      }
  498.       } while (keepon == TRUE);
  499.       ClipBlit(backup_rp, 0L, 0L, rp, (LONG)left_edge, (LONG)top_edge,
  500.                       (LONG)width, (LONG)height, 0xc0L);
  501.       free_rast_port(backup_rp, width, height);
  502.    }
  503.    return(entry);
  504. }
  505.     /* Build rast port for saving background of pop up cycle list */
  506.  
  507.    STATIC struct RastPort *
  508. create_rast_port(USHORT width, USHORT height, USHORT depth)
  509. {
  510.    struct RastPort  *rp;
  511.  
  512.    if (rp = AllocMem((LONG)(sizeof(struct RastPort) + sizeof(struct BitMap)),
  513.                                (LONG)MEMF_PUBLIC)) {
  514.       struct BitMap  *bm = (struct BitMap *)(rp + 1);
  515.       USHORT i;
  516.  
  517.       /* Init rast port */
  518.       InitRastPort(rp);
  519.       rp->BitMap = bm;
  520.  
  521.       /* Init bitmap structure and allocate bit planes */
  522.       InitBitMap(bm, (LONG)depth, (LONG)width, (LONG)height);
  523.       for (i = 0; i < depth; i++) {
  524.      if (!(bm->Planes[i] = (PLANEPTR)AllocRaster((LONG)width,
  525.                                (LONG)height))) {
  526.         /* Free bitmap */
  527.         for ( ; i > 0; i--) {
  528.            FreeRaster(bm->Planes[i], (LONG)width, (LONG)height);
  529.         }
  530.         FreeMem(rp, (LONG)(sizeof(struct RastPort) +
  531.                             sizeof(struct BitMap)));
  532.         rp = NULL;
  533.         break;
  534.      }
  535.       }
  536.    }
  537.    return(rp);
  538. }
  539.     /* Free rast port for saving background of pop up cycle list */
  540.  
  541.    STATIC VOID
  542. free_rast_port(struct RastPort  *rp, USHORT width, USHORT height)
  543. {
  544.    struct BitMap  *bm = rp->BitMap;
  545.    USHORT i, depth = bm->Depth;
  546.  
  547.    for (i = 0; i < depth; i++) {
  548.       FreeRaster(bm->Planes[i], (LONG)width, (LONG)height);
  549.    }
  550.    FreeMem(rp, (LONG)(sizeof(struct RastPort) + sizeof(struct BitMap)));
  551. }
  552.     /* Change count gadget value */
  553.  
  554.    VOID
  555. change_count_gadget(struct ExtendedGadget  *egad)
  556. {
  557.    struct Window     *win = egad->eg_GadgetList->gl_Window;
  558.    struct MsgPort    *up  = win->UserPort;
  559.    struct Gadget     *gad = &egad->eg_Gadget;
  560.    struct CountData  *co = (struct CountData *)(egad + 1);
  561.    LONG   min = co->co_Min, max = co->co_Max, count = co->co_Value;
  562.    ULONG  old_idcmp_flags = win->IDCMPFlags;
  563.    USHORT max_delay = MAX_COUNT_DELAY, delay = MAX_COUNT_DELAY;
  564.    SHORT  count_change, middle = gad->LeftEdge + gad->Width / 2;
  565.    BOOL   keepon = TRUE;
  566.  
  567.    ModifyIDCMP(win, (LONG)(MOUSEBUTTONS | INTUITICKS));
  568.  
  569.    /* Calc new delay and change value with new mouse pos */
  570.    if (win->MouseX > middle) {
  571.       count_change = +1;
  572.       if (count < max) {
  573.      count++;
  574.       }
  575.    } else {
  576.       count_change = -1;
  577.       if (count > min) {
  578.      count--;
  579.       }
  580.    }
  581.    co->co_Value = count;
  582.    print_count_text(egad, TRUE);
  583.  
  584.    /* Change count value depending on mouse position (busy loop) */
  585.    do {
  586.       struct IntuiMessage  *msg;
  587.       SHORT  mouse_x = win->MouseX;
  588.       USHORT distance, new_delay;
  589.  
  590.       /* Calc new delay and change value with new mouse pos */
  591.       if (mouse_x > middle) {
  592.      distance     = mouse_x - middle;
  593.      count_change = +1;
  594.       } else {
  595.      distance = middle - mouse_x;
  596.      count_change = -1;
  597.       }
  598.       if (distance > MAX_COUNT_DISTANCE) {
  599.      distance = MAX_COUNT_DISTANCE;
  600.       }
  601.       new_delay = MAX_COUNT_DELAY - distance / MAX_COUNT_STEP_SIZE;
  602.       if (new_delay != max_delay) {
  603.      max_delay = delay = new_delay;
  604.       }
  605.       if (msg = (struct IntuiMessage *)GetMsg(up)) {
  606.      switch (msg->Class) {
  607.         case INTUITICKS :
  608.            if (max_delay) {
  609.  
  610.           /* Delayed change of count value */
  611.           if (! --delay) {
  612.              if ((count + count_change) >= min &&
  613.                         (count + count_change) <= max) {
  614.             co->co_Value = count += count_change;
  615.             print_count_text(egad, TRUE);
  616.              }
  617.              delay = max_delay;
  618.           }
  619.            }
  620.            break;
  621.  
  622.         case MOUSEBUTTONS :
  623.            if (msg->Code == SELECTUP) {
  624.           keepon = FALSE;
  625.            }
  626.            break;
  627.      }
  628.      ReplyMsg((struct Message *)msg);
  629.       }
  630.       if (! max_delay) {
  631.  
  632.      /* Undelayed change of count value */
  633.      if ((count + count_change) >= min && (count + count_change) <=
  634.                                       max) {
  635.         co->co_Value = count += count_change;
  636.         print_count_text(egad, TRUE);
  637.         timer_delay(0L, MIN_COUNT_DELAY_MICROS);
  638.      }
  639.       }
  640.    } while (keepon == TRUE);
  641.    ModifyIDCMP(win, old_idcmp_flags);
  642.  
  643.    /* Restore normal count gadget state (unselected) */
  644.    if ((gad->Flags & GADGHIGHBITS) == GADGHCOMP) {
  645.       RefreshGList(gad, win, (LONG)NULL, 1L);   /* complement gadget select box */
  646.    }
  647.    gad->Flags &= ~SELECTED;
  648.    RefreshGList(gad, win, (LONG)NULL, 1L);
  649. }
  650.     /* Delay function - can't use Delay() from DOS (no process) */
  651.  
  652.    VOID
  653. timer_delay(ULONG seconds, ULONG micros)
  654. {
  655.    struct MsgPort      *port;
  656.    struct timerequest  *timer;
  657.  
  658.    if (port = CreatePort(NULL, 0L)) {
  659.       if (timer = (struct timerequest *)CreateExtIO(port, (LONG)
  660.                           sizeof(struct timerequest))) {
  661.      if (!OpenDevice(TIMERNAME, (LONG)UNIT_VBLANK, (struct IORequest *)
  662.                                    timer, 0L)) {
  663.         timer->tr_node.io_Command = TR_ADDREQUEST;
  664.         timer->tr_time.tv_secs    = seconds;
  665.         timer->tr_time.tv_micro   = micros;
  666.         DoIO((struct IORequest *)timer);
  667.         CloseDevice((struct IORequest *)timer);
  668.      }
  669.      DeleteExtIO((struct IORequest *)timer);
  670.       }
  671.       DeletePort(port);
  672.    }
  673. }
  674.     /* Print gadget text */
  675.  
  676.    VOID
  677. print_gadget_text(struct ExtendedGadget  *egad)
  678. {
  679.    BYTE *text;
  680.  
  681.    if (text = egad->eg_Text) {
  682.       struct GadgetList  *gl = egad->eg_GadgetList;
  683.       struct RenderInfo  *ri = gl->gl_RenderInfo;
  684.       struct Window      *win = gl->gl_Window;
  685.       struct RastPort    *rp = win->RPort;
  686.       struct Gadget      *gad = &egad->eg_Gadget;
  687.       struct TextAttr    *ta = egad->eg_TextAttr;
  688.       USHORT flags = (egad->eg_DataFlags &
  689.         GADGET_DATA_FLAG_TEXT_COLOR2 ? TEXT_DATA_FLAG_ABSOLUTE_POS |
  690.                TEXT_DATA_FLAG_COLOR2 : TEXT_DATA_FLAG_ABSOLUTE_POS),
  691.          left_edge = gad->LeftEdge + egad->eg_TextLeftEdge,
  692.          top_edge = gad->TopEdge + egad->eg_TextTopEdge;
  693.  
  694.       if (egad->eg_Flags & EXTENDED_GADGET_FLAG_HOTKEY) {
  695.      BYTE   *buffer;
  696.      LONG   len = strlen(text) + 1;
  697.      USHORT pos = egad->eg_HotkeyPos;
  698.  
  699.      if (pos < len && (buffer = AllocMem(len, (LONG)MEMF_PUBLIC))) {
  700.         BYTE   c;
  701.         USHORT save_left_edge = left_edge;
  702.  
  703.         /* Print text part before hotkey */
  704.         strcpy(buffer, text);
  705.         if (pos > 1) {
  706.            *(buffer + pos - 1) = '\0';
  707.            left_edge          += print_text(ri, win, buffer, left_edge,
  708.                   top_edge, TEXT_DATA_TYPE_TEXT, flags, ta);
  709.         }
  710.  
  711.         /* Print and underline hotkey character */
  712.         if (pos < (len - 2)) {
  713.            c                   = *(buffer + pos + 1);
  714.            *(buffer + pos + 1) = '\0';
  715.         }
  716.         save_left_edge = left_edge;
  717.         left_edge     += print_text(ri, win, buffer + pos, left_edge,
  718.                   top_edge, TEXT_DATA_TYPE_TEXT, flags, ta);
  719.         SetDrMd(rp, (LONG)JAM1);
  720.         SetAPen(rp, (LONG)(egad->eg_DataFlags &
  721.                 GADGET_DATA_FLAG_TEXT_COLOR2 ? ri->ri_TextPen2 :
  722.                               ri->ri_TextPen1));
  723.         RectFill(rp, (LONG)save_left_edge, (LONG)(top_edge +
  724.             egad->eg_TextFont->tf_YSize), (LONG)(left_edge - 1),
  725.                 (LONG)(top_edge + egad->eg_TextFont->tf_YSize));
  726.         /* Print text part after hotkey */
  727.         if (pos < (len - 2)) {
  728.            *(buffer + pos + 1) = c;
  729.            print_text(ri, win, buffer + pos + 1, left_edge, top_edge,
  730.                         TEXT_DATA_TYPE_TEXT, flags, ta);
  731.         }
  732.         FreeMem(buffer, len);
  733.      } else {
  734.         print_text(ri, win, text, left_edge, top_edge,
  735.                         TEXT_DATA_TYPE_TEXT, flags, ta);
  736.      }
  737.       } else {
  738.      print_text(ri, win, text, left_edge, top_edge, TEXT_DATA_TYPE_TEXT,
  739.                                  flags, ta);
  740.       }
  741.    }
  742. }
  743.     /* Print cycle text */
  744.  
  745.    VOID
  746. print_cycle_text(struct ExtendedGadget  *egad)
  747. {
  748.    struct GadgetList  *gl = egad->eg_GadgetList;
  749.    struct RenderInfo  *ri = gl->gl_RenderInfo;
  750.    struct Window      *win = gl->gl_Window;
  751.    struct RastPort    *rp = win->RPort;
  752.    struct CycleData   *cy = (struct CycleData *)
  753.                    (gl->gl_Gadgets[egad->eg_DataEntry] + 1);
  754.    struct TextAttr    *text_attr = egad->eg_TextAttr;
  755.    struct IntuiText   itext;
  756.    BYTE   *text = get_language_text(cy->cy_ActiveText,
  757.                           gl->gl_LanguageTextArray);
  758.    USHORT flags = (egad->eg_DataFlags &
  759.         GADGET_DATA_FLAG_TEXT_COLOR2 ? TEXT_DATA_FLAG_ABSOLUTE_POS |
  760.                TEXT_DATA_FLAG_COLOR2 : TEXT_DATA_FLAG_ABSOLUTE_POS),
  761.       left_edge = cy->cy_LeftEdge, top_edge = cy->cy_TopEdge,
  762.       width = cy->cy_Width, height = cy->cy_Height;
  763.  
  764.    itext.IText     = (UBYTE *)text;
  765.    itext.ITextFont = text_attr;
  766.    SetDrMd(rp, (LONG)JAM1);
  767.    SetAPen(rp, (LONG)ri->ri_BackPen);
  768.    RectFill(rp, (LONG)left_edge, (LONG)top_edge, (LONG)(left_edge + width -
  769.                      1), (LONG)(top_edge + height - 1));
  770.    print_text(ri, win, text, left_edge + (SHORT)(width -
  771.         IntuiTextLength(&itext)) / 2, top_edge, TEXT_DATA_TYPE_TEXT,
  772.                               flags, text_attr);
  773. }
  774.     /* Print count text */
  775.  
  776.    VOID
  777. print_count_text(struct ExtendedGadget  *egad, BOOL print_new)
  778. {
  779.    struct GadgetList  *gl = egad->eg_GadgetList;
  780.    struct RenderInfo  *ri = gl->gl_RenderInfo;
  781.    struct Window      *win = gl->gl_Window;
  782.    struct RastPort    *rp = win->RPort;
  783.    struct CountData   *co = (struct CountData *)
  784.                    (gl->gl_Gadgets[egad->eg_DataEntry] + 1);
  785.    struct TextAttr    *text_attr = egad->eg_TextAttr;
  786.    USHORT type = (egad->eg_DataFlags & GADGET_DATA_FLAG_COUNT_SIGNED_DEC ?
  787.                          TEXT_DATA_TYPE_NUM_SIGNED_DEC :
  788.                        TEXT_DATA_TYPE_NUM_UNSIGNED_DEC),
  789.       gflags = egad->eg_Gadget.Flags,
  790.       tflags = (egad->eg_DataFlags & GADGET_DATA_FLAG_TEXT_COLOR2 ?
  791.            TEXT_DATA_FLAG_ABSOLUTE_POS | TEXT_DATA_FLAG_PLACE_LEFT |
  792.                TEXT_DATA_FLAG_COLOR2 : TEXT_DATA_FLAG_ABSOLUTE_POS |
  793.                          TEXT_DATA_FLAG_PLACE_LEFT),
  794.       left_edge = co->co_LeftEdge, top_edge = co->co_TopEdge,
  795.       width = co->co_Width, height = co->co_Height;
  796.  
  797.    /* Clear area for new value */
  798.    if ((gflags & SELECTED) && (gflags & GADGHIGHBITS) == GADGHCOMP) {
  799.       tflags |= TEXT_DATA_FLAG_COMPLEMENT | INTERNAL_TEXT_DATA_FLAG_COUNT;
  800.       SetAPen(rp, (LONG)(ri->ri_BackPen ^ ((1 << ri->ri_ScreenDepth) - 1)));
  801.    } else {
  802.       SetAPen(rp, (LONG)ri->ri_BackPen);
  803.    }
  804.    SetDrMd(rp, (LONG)JAM1);
  805.    RectFill(rp, (LONG)left_edge, (LONG)top_edge,
  806.           (LONG)(left_edge + width - 1), (LONG)(top_edge + height - 1));
  807.  
  808.    /* Print new value if requested */
  809.    if (print_new) {
  810.       print_text(ri, win, (BYTE *)co->co_Value, left_edge + width,
  811.                      top_edge, type, tflags, text_attr);
  812.    }
  813. }
  814.     /* Print list view text */
  815.  
  816.    VOID
  817. print_list_view_text(struct ExtendedGadget  *egad)
  818. {
  819.    struct GadgetList  *gl = egad->eg_GadgetList;
  820.    struct Window      *win = gl->gl_Window;
  821.    struct RastPort    *rp = win->RPort;
  822.    struct Layer       *layer = rp->Layer;
  823.    struct Region      *region;
  824.  
  825.    /* Calc offsets for inner window */
  826.    LockLayerRom(layer);
  827.    if (region = NewRegion()) {
  828.       struct RenderInfo    *ri = gl->gl_RenderInfo;
  829.       struct Rectangle     rect;
  830.       struct Region        *old_region;
  831.       struct ClipRect      *old_cliprects;
  832.       struct ListViewData  *lv = (struct ListViewData *)
  833.                    (gl->gl_Gadgets[egad->eg_DataEntry] + 1);
  834.       struct TextAttr      *ta = egad->eg_TextAttr;
  835.       struct Node          *node = lv->lv_TopNode;
  836.       ULONG  gflags = egad->eg_DataFlags;
  837.       USHORT i, tflags = (gflags & GADGET_DATA_FLAG_TEXT_COLOR2 ?
  838.                TEXT_DATA_FLAG_COLOR2 | TEXT_DATA_FLAG_ABSOLUTE_POS |
  839.             TEXT_DATA_FLAG_BACK_FILL : TEXT_DATA_FLAG_ABSOLUTE_POS |
  840.                           TEXT_DATA_FLAG_BACK_FILL),
  841.          left_edge = lv->lv_LeftEdge, top_edge = lv->lv_TopEdge,
  842.          width = lv->lv_Width, height = lv->lv_Height,
  843.          entries = lv->lv_ListEntries, visible = lv->lv_VisibleEntries,
  844.          entry_height = lv->lv_EntryHeight, top = lv->lv_TopEntry;
  845.  
  846.       /* Create clipping region around list view entry area */
  847.       rect.MinX = left_edge;
  848.       rect.MaxX = left_edge + width - 1;
  849.       rect.MinY = top_edge;
  850.       rect.MaxY = top_edge + height - 1;
  851.       OrRectRegion(region, &rect);
  852.  
  853.       /* Before installing clipping region save old clipping rectangles */
  854.       old_cliprects     = layer->_cliprects;
  855.       layer->_cliprects = NULL;
  856.       old_region = InstallClipRegion(layer, region);
  857.  
  858.       /* Print list view entry text with clipping */
  859.       SetDrMd(rp, (LONG)JAM1);
  860.       SetAPen(rp, (LONG)ri->ri_BackPen);
  861.       for (i = visible; i; i--, top++, top_edge += entry_height) {
  862.      if (top < entries) {
  863.         BYTE   *text = node->ln_Name;
  864.         USHORT tflags, text_width;
  865.  
  866.         /* Check for alternate entry text color */
  867.         if ((gflags & GADGET_DATA_FLAG_LISTVIEW_ENTRY_COLOR) &&
  868.                                    *text == 1) {
  869.            text++;
  870.            tflags = (gflags & GADGET_DATA_FLAG_TEXT_COLOR2 ?
  871.             TEXT_DATA_FLAG_ABSOLUTE_POS | TEXT_DATA_FLAG_BACK_FILL :
  872.                TEXT_DATA_FLAG_COLOR2 | TEXT_DATA_FLAG_ABSOLUTE_POS |
  873.                           TEXT_DATA_FLAG_BACK_FILL);
  874.         } else {
  875.            tflags = (gflags & GADGET_DATA_FLAG_TEXT_COLOR2 ?
  876.                TEXT_DATA_FLAG_COLOR2 | TEXT_DATA_FLAG_ABSOLUTE_POS |
  877.             TEXT_DATA_FLAG_BACK_FILL : TEXT_DATA_FLAG_ABSOLUTE_POS |
  878.                           TEXT_DATA_FLAG_BACK_FILL);
  879.         }
  880.  
  881.         /* Print entry text and clear rest of line */
  882.         text_width = print_text(ri, win, text, left_edge, top_edge,
  883.                        TEXT_DATA_TYPE_TEXT, tflags, ta);
  884.         if (text_width < width) {
  885.            RectFill(rp, (LONG)(left_edge + text_width), (LONG)top_edge,
  886.                 (LONG)(left_edge + width - 1), (LONG)(top_edge +
  887.                              entry_height - 1));
  888.         }
  889.         node = node->ln_Succ;
  890.      } else {
  891.         break;
  892.      }
  893.       }
  894.       if (i) {
  895.      RectFill(rp, (LONG)left_edge, (LONG)top_edge, (LONG)(left_edge +
  896.                width - 1), (LONG)(top_edge + i * entry_height - 1));
  897.       }
  898.  
  899.       /* Highlite selected entry */
  900.       if (gflags & GADGET_DATA_FLAG_LISTVIEW_SHOW_SELECTED) {
  901.      USHORT selected = lv->lv_SelectedEntry;
  902.  
  903.      /* Check if visible */
  904.      top = lv->lv_TopEntry;
  905.      if (selected < entries && selected >= top &&
  906.                            selected < (top + visible)) {
  907.         top_edge = lv->lv_TopEdge + (selected - top) * entry_height;
  908.         SetDrMd(rp, (LONG)COMPLEMENT);
  909.         RectFill(rp, (LONG)left_edge, (LONG)top_edge, (LONG)(left_edge +
  910.                width - 1), (LONG)(top_edge + ta->ta_YSize - 1));
  911.      }
  912.       }
  913.  
  914.       /* Remove clipping region and restore old clipping rectangles */
  915.       InstallClipRegion(layer, old_region);
  916.       layer->_cliprects = old_cliprects;
  917.       DisposeRegion(region);
  918.    }
  919.    UnlockLayerRom(layer);
  920. }
  921.